/*
Copyright (c) 2010, Advanced Micro Devices
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted 
provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions 
and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this list of 
conditions and the following disclaimer in the documentation and/or other materials provided 
with the distribution.

Neither the name of Advanced Micro Devices nor the names of its contributors may be used to endorse 
or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef PARSER_HDR
#define PARSER_HDR

/*! \file
 *   \brief Lexer and Parser for Pipeline Kit    
 *   \author Benedict R. Gaster 
 *   
 *   \version 0.1
 *   \date March 2010
 */


#include "platform.h"

#include <string>
#include <map>
#include <stdexcept>
#include <sstream>
 
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <algorithm>


#ifdef __APPLE__
#include "/boost_1_43_0/boost/variant.hpp"
#include "/boost_1_43_0/boost/variant/get.hpp"
#else//Windows
#include <boost/variant.hpp>
#include <boost/variant/get.hpp>
#endif

#include "ast.hpp"

namespace amd {

class Parser
{
public:
	enum TokenType 
	{
		NONE,
		NAME,
		NUMBER,
		STRING,
		END,
		NOT='!',
		LHPAREN='(',
		RHPAREN=')',
		MULTIPLY='*',
		PLUS='+',
		COMMA=',',
		MINUS='-',
		DIVIDE='/',
		COLON=':',
		SEMI=';',
		LT='<',
		ASSIGN='=',
		GT='>',	
		LHBRACE='{',
		RHBRACE='}',

		LE,     // <=
		GE,     // >=
		EQ,     // ==
		NE,     // !=
		AND,    // &&
		OR,      // ||    

		ARROW,   // ->

		// Keywords,
		TRUETK,
		FALSETK,
		PIPELINE,
		GLOBAL,
		LOCAL,
		BUFFER,
		IMAGE2D,
		IMAGE3D,
		UNIFORM,
		STAGE,
		GRAPH,
		CODECL,
		CODECPP,
		KERNEL,
		INPUT,
		OUTPUT,
		INOUT
    };
      
	Parser (const std::string & program) 
		: program_ (program)
	{  
		symbols_ ["pi"] = 3.1415926535897932385;
		symbols_ ["e"]  = 2.7182818284590452354;      
    }
  
	const double evaluate ();
	const double evaluate (const std::string & program);
 
	double & operator[] (const std::string & key) 
	{ 
		return symbols_[key]; 
	}
 	
	std::map<std::string, double> symbols_;	

	ASTExpr parseExpr(void)
	{
		pWord_ = program_.c_str();
		type_  = NONE;

		return expression();
	}

	ASTMemory parseMemory(void)
	{
		pWord_ = program_.c_str();
		type_  = NONE;

		Maybe<ASTMemory>::MaybeType mem = memory();

		return Maybe<ASTMemory>::toJust(mem);
	}

	ASTPipeline parsePipeline(void)
	{
		pWord_ = program_.c_str();
		type_  = NONE;

		return pipeline();
	}

	/* \brief Translate token into string form.
	 *
	 * \param token is the token to be translated into a string
	 * \return string representation of token
	 */
	static std::string stringifyToken(TokenType token);

private:
	std::string program_;
 
	const void skipWhiteSpaceComments(void);
	const TokenType getToken (const bool ignoreSign = false);

	ASTExpr atomic(const bool getTok = true);
	ASTExpr term(const bool getTok = true);
	ASTExpr expression(const bool getTok = true);

	Maybe<ASTMemory>::MaybeType memory(const bool getTok = true);
	ASTBuffer buffer(const bool getTok = true);
	ASTImage2D image2D(const bool getTok = true);
	ASTImage3D image3D(const bool getTok = true);
	ASTAttributeList attributes(const bool getTok = true, const bool named = false);

	bool environment(ASTVarDefMap& env, const bool getTok = true);

	Maybe<ASTUniform>::MaybeType uniform(const bool getTok = true);

	Maybe<ASTCode>::MaybeType code(const bool getTok = true);

	ASTTypeVarList kernelArguments(const bool getTok = true);
	Maybe<ASTKernel>::MaybeType kernel(const bool getTok = true);

	ASTTypeList stageArguments(const bool getTok = true);
	Maybe<ASTStage>::MaybeType stage(const bool getTok = true);

	Maybe<ASTGraph>::MaybeType graph(const bool getTok = true); 

	ASTPipeline pipeline(const bool getTok = true);

	bool given(TokenType type, const bool getTok = true);

	const char * pWord_;
	const char * pWordStart_;
  
	TokenType type_;
	std::string word_;
	double value_;

	typedef std::map<std::string, TokenType> keywordType;
	typedef keywordType::value_type keywordPairType;
	static keywordType keywords_;	
	
	static keywordPairType keywordInitializers_[];

	static std::string types_[];

	static bool isType(std::string type);

#if 0
  const double commaList (const bool get);
  const Expression expression (const bool get);
  const double comparison (const bool get);
  const double addSubtract (const bool get);
  const double term (const bool get);      
  const double primary (const bool get);  
#endif

  inline void checkToken (const TokenType wanted)
  {
		if (type_ != wanted) {
			std::ostringstream s;
			s << "'" << static_cast <char> (wanted) << "' expected.";
			throw std::runtime_error (s.str ());    
		}
  }
};
 
}; // namespace amd
 
#endif // PARSER_HDR
 